local hsocket = {}
-- require "socket"
-- require "nvm"
-- require "hconfig"
-- -- 外部接口调用
-- require "h232"
-- require "tool"
-- require "h485"
-- require "hconfig"
-- 网络参数
hsocket.dtu = {
    -- 异步接口
    async_client = {},
    client_connected = { false, false, false, false },
    ClientCloseFlag = { 0, 0, 0, 0 },
    client_recv_flag = 0,
    -- 断网检测
    check_cnt = 0,
}
local net_send_buff = ""
local net_recv_buff = ""
local net_t = {
    QN = "",
    MN = "",
    ST = "",
    PW = "",
    CN = "",
    CP = "",
    CP1 = "",
    CP2 = "",
    CP3 = "",
    CP4 = "",
    CP5 = "",
    CP6 = "",
    len = "",
    CRC = ""
}
-- bTimeSyned ：时间是否已经成功同步过
local bTimeSyned


local send_queue = {}
local zrecv_buff = zbuff.create(4096)


function hsocket.printTime()
    local tClock = os.date("*t")
    log.info("printTime",
        string.format("%04d-%02d-%02d %02d:%02d:%02d", tClock.year,
            tClock.month, tClock.day, tClock.hour, tClock.min,
            tClock.sec))
end

-- 转义函数
local function dtu2serial(data)
    local keychars = { 0xfe, 0xfd }
    local keychars_replace = { 0xfd, 0xee, 0xfd, 0xed }
    local res, j = "", 1
    if #data == 0 then
        return res
    end
    for i = 1, #data, 1 do
        if j > #data then
            break
        end
        if j < #data - 1 then
            if (data:byte(j) == keychars_replace[1]) and (data:byte(j + 1) == keychars_replace[2]) then
                res = res .. string.format("%02x", keychars[1])
                j = j + 1
            elseif (data:byte(j) == keychars_replace[3]) and (data:byte(j + 1) == keychars_replace[4]) then
                res = res .. string.format("%02x", keychars[2])
                j = j + 1
            else
                res = res .. string.format("%02x", data:byte(j))
            end
        else
            res = res .. string.format("%02x", data:byte(j))
        end
        j = j + 1
    end
    return string.fromHex(res)
end
function hsocket.is_ready()
    local ret
    if hconfig.STA_4G == 2  then
        ret, _ = socket.adapter(socket.LWIP_STA)
    elseif hconfig.STA_4G == 1 then
        ret, _ = socket.adapter(socket.LWIP_GP)
    else
        ret =false
    end
    return ret
end

--登陆报文
local function login_msg(str)
    return string.fromHex(str)
end

local function net_heart()
    -- body
    if hconfig.NET.heart[1] == 1 then
        return hconfig.NET.heart[2]
    else
        return ""
    end
end



-- socket任务函数
function hsocket.tcp_task(num)
    local succ, buff_full
    local TCP_CLIENT_NAME = "TCP_CLIENT_TASK" .. num
    while true do
        while true do
            if not hsocket.is_ready() then
                log.info("tcp_task", "网络初始化失败!")
                if not sys.waitUntil("STA_4G_READY", 300000) then
                    if hconfig.LAN_MODE == 0 then
                        pm.reboot()
                    end
                end
            else
                if hconfig.STA_4G > 0 then
                    break
                end
                sys.wait(1000)
            end
        end
        if hconfig.NET.ser[num][3] ~= 0 then
            -- socket.debug(hsocket.dtu.async_client[num], true)
            hsocket.dtu.async_client[num] = socket.create(nil, TCP_CLIENT_NAME)
            if not hsocket.dtu.async_client[num] then
                log.info("[socket]->create ", num, " failed.")
                goto EXCEPTION_PROC
            end

            succ = socket.config(hsocket.dtu.async_client[num])
            if not succ then
                log.info("[socket]->hconfig ", num, " failed.")
                goto EXCEPTION_PROC
            end

            succ = libnet.connect(TCP_CLIENT_NAME, 15000, hsocket.dtu.async_client[num], hconfig.NET.ser[num][1],
                hconfig.NET.ser[num][2])
            if not succ then
                log.info("[socket]->connect ", num, " failed.")
                goto EXCEPTION_PROC
            end
            log.info("[socket]->connect", num, succ)

            if succ then
                if hconfig.NET.reg[1] == 1 and hconfig.NET.reg[2] ~= "" then
                    succ, buff_full = libnet.tx(TCP_CLIENT_NAME, 15000, hsocket.dtu.async_client[num],
                        login_msg(hconfig.NET.reg[2]))
                    if not succ then
                        log.info("[socket]->login failed", num, succ, buff_full)
                        goto EXCEPTION_PROC
                    end
                    log.info("[socket]->login", num, succ)
                end
                hsocket.dtu.client_connected[num] = true
                while true do
                    if (hconfig.NET.heart[1] == 1 and hconfig.NET.heart[2] ~= "") then
                        succ, buff_full = libnet.tx(TCP_CLIENT_NAME, 15000, hsocket.dtu.async_client[num], net_heart())
                        log.info("[socket]->heart", num, succ, buff_full)
                    end
                    succ = socket.wait(hsocket.dtu.async_client[num])
                    if succ == true then
                        if hsocket.dtu.ClientCloseFlag[num] == 1 then
                            log.info("[socket]->server ClientCloseFlag", num)
                            hconfig.NET = fskv.get("NET")
                            hsocket.dtu.ClientCloseFlag[num] = 0
                            break
                        end
                        sys.wait(60000)
                    else
                        log.info("[socket]->wait", num, succ)
                        hsocket.dtu.check_cnt = hsocket.dtu.check_cnt + 1
                        if hsocket.dtu.check_cnt >= 3 then
                            hsocket.dtu.check_cnt = 0
                            break
                        end
                        sys.wait(3000)
                    end
                end
            end
            -- 出现异常
            ::EXCEPTION_PROC::
            log.info("[socket]->exception", num)
            hsocket.dtu.client_connected[num] = false
            if hsocket.dtu.async_client[num] then
                libnet.close(TCP_CLIENT_NAME, 5000, hsocket.dtu.async_client[num])
                socket.release(hsocket.dtu.async_client[num])
                hsocket.dtu.async_client[num] = nil
            end
            log.info("[socket]->close", num)
        end
        sys.wait(10000)
    end
end

function hsocket.hsocket_send(data, num, per)
    -- num:指定发送的socket序号，0表示发送到所有已连接的socket
    table.insert(send_queue, { data = data, num = num })
    -- sysplus.sendMsg("TCP_CLIENT_TASK", socket.EVENT, 0)
end

local function hsocket_send_task()
    local resu, buff_full, is_break = false, false, false
    while true do
        if #send_queue > 0 then
            local item = table.remove(send_queue, 1)
            log.info("[socket]->send queue:", item.num)
            for i = 1, #hsocket.dtu.client_connected do
                if hsocket.dtu.client_connected[i] then
                    if hconfig.NET.ser[i][3] == 3 then
                        log.info("[socket]->S", i, "only recv")
                    else
                        if (item.num > 0) and (item.num == i) then
                            resu, buff_full = socket.tx(hsocket.dtu.async_client[i], item.data)
                            is_break = true
                        elseif item.num == 0 then
                            resu, buff_full = socket.tx(hsocket.dtu.async_client[i], item.data)
                        end
                        resu, _ = socket.wait(hsocket.dtu.async_client[i])
                        if not resu then
                            hsocket.dtu.client_connected[i] = false
                        end
                        if buff_full then
                            table.insert(send_queue, 1, item)
                            sys.wait(3000)
                            is_break = true
                        end
                        if is_break then
                            is_break = false
                            break
                        end
                    end
                end
            end
            if hconfig.LAN_MODE == 1 then
                hlan.write(item.data)
            end
        else
            sys.wait(500)
        end
    end
end
-- 异步回调接收数据
local function hsocket_read_task()
    while true do
        if next(hsocket.dtu.async_client) == nil then
            sys.wait(2000)
        else
            -- log.info("hsocket_read_task", "check")
            for i = 1, 4, 1 do
                -- log.info("hsocket_read_task", i, hsocket.dtu.client_connected[i])
                if hsocket.dtu.client_connected[i] then
                    zrecv_buff:clear()
                    zrecv_buff:seek(0)
                    -- libnet.wait("HSOCKET_READ_TASK", 1000,hsocket.dtu.async_client[i])
                    local resu = socket.rx(hsocket.dtu.async_client[i], zrecv_buff)
                    if not resu then
                        hsocket.dtu.ClientCloseFlag[i] = 1
                        hsocket.dtu.client_connected[i] = false
                        log.info("socket.rx error", i)
                    elseif zrecv_buff:used() > 0 then
                        local data = zrecv_buff:query(0, zrecv_buff:used())
                        log.info("server recv:", i, #data, data:toHex())
                        hsocket.dtu.client_recv_flag = 1
                        if h485.cmd_parse(data) == 0 and hsocket.is_ready() then
                            if data:byte(1) == 0x00 and data:byte(2) == 0x01 and data:byte(3) == 0x02 then
                                net_recv_buff = dtu2serial(data)
                                htf.tf_write_data(string.format("[socket %d]", i), net_recv_buff)
                                if hconfig.NET.ser[i][3] ~= 2 then
                                    h232.write(net_recv_buff)
                                    h485.write(net_recv_buff)
                                end
                                net_recv_buff = ""
                            else
                                h232.write(data)
                                h485.write(data)
                            end
                        else
                            hsocket.hsocket_send(h485.print_hconfig_net(), i)
                        end
                        hsocket.dtu.client_recv_flag = 0
                    end
                end
            end
            -- resu = libnet.wait("HSOCKET_READ_TASK", 1000)
            sys.wait(500)
        end
    end
end

function hsocket.hsocket_resp_pack(flag)
    local tClock = os.date("*t")
    local dev_num = nvm.get("DEV_NUMBER")
    local len
    net_t.QN = string.format("QN=%04d%02d%02d%02d%02d%02d%03d;", tClock.year,
        tClock.month, tClock.day, tClock.hour, tClock.min,
        tClock.sec, 0)
    net_t.MN = string.format("MN=%s;Flag=5;", dev_num)
    net_t.ST = string.format("ST=%d;", 22)
    net_t.PW = string.format("PW=%d;", 123456)
    net_t.CP = string.format("CP=&&")
    net_t.CN = string.format("CN=%d;", 9024)
    net_t.CP1 = string.format("CmdResult=%d&&", flag)
    len = string.len(net_t.QN) + string.len(net_t.MN) + string.len(net_t.ST) +
        string.len(net_t.PW) + string.len(net_t.CP) + string.len(net_t.CN) +
        string.len(net_t.CP1)
    net_t.len = string.format("%04d", len)
    net_send_buff = net_t.QN .. net_t.MN .. net_t.ST .. net_t.CN .. net_t.PW ..
        net_t.CP .. net_t.CP1
    net_t.CRC = string.format("%04X", tool.Crc16_Checkout(net_send_buff))
    net_send_buff = "##" .. net_t.len .. net_send_buff .. net_t.CRC .. "\r\n"
    hsocket.hsocket_send(net_send_buff, 0, 0)
    net_send_buff = ""
end

function hsocket.hdev_status_pack()
    local buff = {}
    local tmp
    local hexstr = ""
    buff[1] = 0x24
    buff[2] = 0x23
    for i = 1, 12, 1 do
        if hconfig.DEV_NUMBER:byte(i) == nil then
            buff[2 + i] = 0x00
        else
            buff[2 + i] = hconfig.DEV_NUMBER:byte(i)
        end
    end
    buff[15] = h485.Sensor_val.rs232_flag
    buff[16] = h485.Sensor_val.usb_flag
    buff[17] = h485.Sensor_val.csq[2]
    buff[18] = h485.Sensor_val.gps_flag

    tmp = pack.pack("<f", tonumber(h485.Sensor_val.longitude) * 10000000)
    buff[19] = tmp:byte(1)
    buff[20] = tmp:byte(2)
    buff[21] = tmp:byte(3)
    buff[22] = tmp:byte(4)

    tmp = pack.pack("<f", tonumber(h485.Sensor_val.latitude) * 10000000)
    buff[23] = tmp:byte(1)
    buff[24] = tmp:byte(2)
    buff[25] = tmp:byte(3)
    buff[26] = tmp:byte(4)
    for i = 1, 20, 1 do
        if h485.Sensor_val.iccid:byte(i) ~= nil then
            buff[26 + i] = h485.Sensor_val.iccid:byte(i)
        else
            buff[26 + i] = 0x00
        end
    end
    buff[47] = 0x23
    buff[48] = 0x24
    for i = 1, 48, 1 do
        if buff[i] == nil then
            log.info("buff[i]==nil", i)
        else
            hexstr = hexstr .. string.format("%02x", buff[i])
        end
    end
    -- log.info("tim tx:",string.fromHex(hexstr))
    hsocket.hsocket_send(string.fromHex(hexstr), 0, 0)
end

sys.taskInitEx(function()
    while true do
        if not hsocket.is_ready() and not sys.waitUntil("STA_4G_READY", 300000) then
            log.info("网络初始化失败!")
            if hconfig.LAN_MODE == 0 then
                pm.reboot()
            end
        else
            if hconfig.STA_4G>0 then
                break
            end
            sys.wait(1000)
        end
    end
    for k, v in pairs(hconfig.NET.ser or {}) do
        if v[3] ~= 0 then
            log.warn("----------------------- TCP/UDP is start! --------------------------------------")
            log.warn("启动socket任务:", k)
            sys.taskInitEx(hsocket.tcp_task, "TCP_CLIENT_TASK" .. k, nil, k)
        end
    end
    while true do
        if hsocket.dtu.client_recv_flag == 0 then
            if h485.Sensor_val.iccid == "" then
                h485.update_iccid()
            end
        end
        if hsocket.dtu.client_connected[1] and hsocket.dtu.client_connected[2] then
            hled.led_sta(3);
        elseif hsocket.dtu.client_connected[1] then
            hled.led_sta(1);
        elseif hsocket.dtu.client_connected[2] then
            hled.led_sta(2);
        end
        if not hsocket.dtu.client_connected[1] and not hsocket.dtu.client_connected[2] then
            hled.led_sta(0);
        end
        sys.wait(1000)
    end
end, "TCP_TASK")


-- sys.subscribe("IP_READY", function(ip, adapter)
--     log.info("hsocket", "recv IP_READY",ip, (adapter or -1))
--     if adapter == socket.LWIP_GP then
--         h485.Sensor_val.sta_4g_flag = 1
--     elseif adapter == socket.LWIP_STA then
--         h485.Sensor_val.sta_4g_flag = 2
--     else
--         h485.Sensor_val.sta_4g_flag = 0
--     end
--     sys.publish("STA_4G_READY")
-- end)

-- 发送任务
sys.taskInitEx(hsocket_send_task, "HSOCKET_SEND_TASK")

-- 接收任务
sys.taskInitEx(hsocket_read_task, "HSOCKET_READ_TASK")

-- ntp任务函数
sys.taskInit(function()
    sys.wait(1000)
    while 1 do
        local is_ready, _ = socket.adapter(socket.LWIP_GP)
        if is_ready then
            log.info("开始执行SNTP")
            socket.sntp()
            local ret = sys.waitUntil("NTP_UPDATE", 5000)
            if ret then
                sys.wait(3000)
                break
            end
        end
        sys.wait(60000) -- 1分钟后重试
    end
end)

return hsocket
